package com.amigo.online.provider;

import javax.sql.DataSource;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

import com.amigo.online.provider.adv.quartz.job.InitHomeAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.InitNearbyAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.InitRecommendAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.InitTantanAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.SettleHomeAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.SettleNearbyAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.SettleRecommendAdvStockJob;
import com.amigo.online.provider.adv.quartz.job.SettleTantanAdvStockJob;

@Configuration
@EnableScheduling
public class QuartzConfig {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 继承org.springframework.scheduling.quartz.SpringBeanJobFactory 实现任务实例化方式
     */
    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;

        @Override
        public void setApplicationContext(final ApplicationContext context) {
            beanFactory = context.getAutowireCapableBeanFactory();
        }

        /**
         * 将job实例交给spring ioc托管 我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
         *
         * @param bundle
         * @return
         * @throws Exception
         */
        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            /**
             * 将job实例交付给spring ioc
             */
            beanFactory.autowireBean(job);
            return job;
        }
    }

    /*
     * quartz初始化监听器
     */
    @Bean
    public QuartzInitializerListener executorListener() {
        return new QuartzInitializerListener();
    }

    /*
     * 通过SchedulerFactoryBean获取Scheduler的实例
     */
    @Bean(name = "Scheduler")
    public Scheduler scheduler() throws Exception {
        return schedulerFactoryBean(jobFactory(applicationContext), null).getScheduler();
    }

    /**
     * 配置任务工厂实例
     *
     * @param applicationContext spring上下文实例
     * @return
     */
    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        /**
         * 采用自定义任务工厂 整合spring实例来完成构建任务 see {@link AutowiringSpringBeanJobFactory}
         */
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    /**
     * 配置任务调度器 使用项目数据源作为quartz数据源
     *
     * @param jobFactory 自定义配置任务工厂
     * @param dataSource 数据源实例
     * @return
     * @throws Exception
     */
    @Bean(destroyMethod = "destroy", autowire = Autowire.NO)
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) throws Exception {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        // 将spring管理job自定义工厂交由调度器维护
        schedulerFactoryBean.setJobFactory(jobFactory);
        // 设置覆盖已存在的任务
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        // 项目启动完成后，等待2秒后开始执行调度器初始化
        schedulerFactoryBean.setStartupDelay(2);
        // 设置调度器自动运行
        schedulerFactoryBean.setAutoStartup(true);
        // 设置数据源，使用与项目统一数据源
        // schedulerFactoryBean.setDataSource(dataSource);
        schedulerFactoryBean.setJobDetails(initTantanAdvStockJobDetail(), initNearbyAdvStockJobDetail(),
                initRecommendAdvStockJobDetail(), initHomeAdvStockJobDetail(), settleTantanAdvStockJobDetail(),
                settleNearbyAdvStockJobDetail(), settleRecommendAdvStockJobDetail(), settleHomeAdvStockJobDetail());
        schedulerFactoryBean.setTriggers(initNearbyAdvStockJobTrigger(), initHomeAdvStockJobTrigger(),
                initRecommendAdvStockJobTrigger(), initTantanAdvStockJobTrigger(), settleNearbyAdvStockJobTrigger(),
                settleHomeAdvStockJobTrigger(), settleRecommendAdvStockJobTrigger(), settleTantanAdvStockJobTrigger());
        // 设置上下文spring bean name
        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
        // 设置配置文件位置
        schedulerFactoryBean.setConfigLocation(new ClassPathResource("/application.properties"));
        return schedulerFactoryBean;
    }

    /**
     * 初始化tantan
     */
    @Bean
    public JobDetail initTantanAdvStockJobDetail() {
        return JobBuilder.newJob(InitTantanAdvStockJob.class).withIdentity("initTantanAdvStockJob").storeDurably()
                .build();
    }

    @Bean
    public Trigger initTantanAdvStockJobTrigger() {
        // CORN 方式，每隔五秒执行一次
        return TriggerBuilder.newTrigger().forJob(initTantanAdvStockJobDetail()).withIdentity("initTantanAdvStockJob")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 58 23 * * ?")).build();
    }

    /**
     * 初始化推荐
     */
    @Bean
    public JobDetail initRecommendAdvStockJobDetail() {
        return JobBuilder.newJob(InitRecommendAdvStockJob.class).withIdentity("initRecommendAdvStockJob").storeDurably()
                .build();
    }

    @Bean
    public Trigger initRecommendAdvStockJobTrigger() {
        // 每隔五秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(initRecommendAdvStockJobDetail())
                .withIdentity("initRecommendAdvStockJob")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 57 23 * * ?")).build();
    }

    /**
     * 初始化首页
     */
    @Bean
    public JobDetail initHomeAdvStockJobDetail() {
        return JobBuilder.newJob(InitHomeAdvStockJob.class).withIdentity("initHomeAdvStockJob").storeDurably().build();
    }

    @Bean
    public Trigger initHomeAdvStockJobTrigger() {
        // 每隔五秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(15)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(initHomeAdvStockJobDetail()).withIdentity("initHomeAdvStockJob")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 56 23 * * ?")).build();
    }

    /**
     * 初始化附近的人
     */
    @Bean
    public JobDetail initNearbyAdvStockJobDetail() {
        return JobBuilder.newJob(InitNearbyAdvStockJob.class).withIdentity("initNearbyAdvStockJob").storeDurably()
                .build();
    }

    @Bean
    public Trigger initNearbyAdvStockJobTrigger() {
        // 每隔五秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(initNearbyAdvStockJobDetail()).withIdentity("initNearbyAdvStockJob")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 55 23 * * ?")).build();
    }

    /**
     * 结算探探
     */
    @Bean
    public JobDetail settleTantanAdvStockJobDetail() {
        return JobBuilder.newJob(SettleTantanAdvStockJob.class).withIdentity("settleTantanAdvStockJob").storeDurably()
                .build();
    }

    @Bean
    public Trigger settleTantanAdvStockJobTrigger() {
        // CORN 方式，每隔五秒执行一次
        return TriggerBuilder.newTrigger().forJob(settleTantanAdvStockJobDetail())
                .withIdentity("settleTantanAdvStockJob").withSchedule(CronScheduleBuilder.cronSchedule("0 2 0 * * ?"))
                .build();
    }

    /**
     * 结算推荐视频
     */
    @Bean
    public JobDetail settleRecommendAdvStockJobDetail() {
        return JobBuilder.newJob(SettleRecommendAdvStockJob.class).withIdentity("settleRecommendAdvStockJob")
                .storeDurably().build();
    }

    @Bean
    public Trigger settleRecommendAdvStockJobTrigger() {
        // 每隔五秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(settleRecommendAdvStockJobDetail())
                .withIdentity("settleRecommendAdvStockJob")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 4 0 * * ?")).build();
    }

    /**
     * 结算首页
     */
    @Bean
    public JobDetail settleHomeAdvStockJobDetail() {
        return JobBuilder.newJob(SettleHomeAdvStockJob.class).withIdentity("settleHomeAdvStockJob").storeDurably()
                .build();
    }

    @Bean
    public Trigger settleHomeAdvStockJobTrigger() {
        // 每隔五秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(settleHomeAdvStockJobDetail()).withIdentity("settleHomeAdvStockJob")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 3 0 * * ?")).build();
    }

    /**
     * 结算附近的人
     */
    @Bean
    public JobDetail settleNearbyAdvStockJobDetail() {
        return JobBuilder.newJob(SettleNearbyAdvStockJob.class).withIdentity("settleNearbyAdvStockJob").storeDurably()
                .build();
    }

    @Bean
    public Trigger settleNearbyAdvStockJobTrigger() {
        // 每隔五秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(20)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(settleNearbyAdvStockJobDetail())
                .withIdentity("settleNearbyAdvStockJob").withSchedule(CronScheduleBuilder.cronSchedule("0 1 0 * * ?"))
                .build();
    }
}
